#include "String.h"
#include "Storage.h"
#include <Support\GAssert.h>
#include <boost/algorithm/string.hpp>

String::String()
{
	init();
}

String::String(const char* str)
{
	size_t stringLengthReceived = strlen(str); 
	if (stringLengthReceived < (DEFAULT_STRING_LENGTH - 1) )
	{
		stringData = _stringData;
		stringDataLength = DEFAULT_STRING_LENGTH;
	}
	else
	{
		stringData = (char*) gStorageManager.New(stringLengthReceived + 1);
		ASSERT(NULL != stringData, "Not Enough Storage for String. Storage Requested = %u", stringLengthReceived);
		stringDataLength = stringLengthReceived + 1;
	}
	stringLength = stringLengthReceived;
	strncpy_s(stringData, stringDataLength, str, stringLengthReceived);
}

String::~String()
{
	if (stringData != _stringData)
		gStorageManager.Delete(stringData);
}

String& String::operator=(const String& str)
{
	set(str.stringData);
	return *this;
}

String& String::operator=(const char* str)
{
	set(str);
	return *this;
}

String& String::operator+=(const String& str)
{
	append(str.stringData);
	return *this;
}
String& String::operator+=(const char* str)
{
	append(str);
	return *this;
}

void String::append(const char* str)
{
	size_t strLength = strlen(str);
	size_t newStrLength = stringLength + strLength;
	if (stringDataLength < (newStrLength - 1))
	{
		char* newBuffer = (char*)gStorageManager.New(newStrLength + 1);
		strncpy_s(newBuffer, stringLength, stringData, stringLength);
		gStorageManager.Delete(stringData);
		stringData = newBuffer;
	}
	strncpy_s(stringData + stringLength, newStrLength, str, strLength);
	stringLength = newStrLength;
	stringDataLength = newStrLength + 1;
}

void String::init()
{
	stringData = _stringData;
	stringLength = 0;
	stringDataLength = DEFAULT_STRING_LENGTH;
}

void String::toLowerCase() { boost::to_lower(stringData); }
void String::toUpperCase() { boost::to_upper(stringData); }


char* String::get() { return (! stringLength)? NULL: stringData; }

void String::set(const char* str) { 
	size_t newStrlength = strlen(str);
	if (newStrlength > (stringDataLength-1))
	{
		if (stringData != _stringData)
			gStorageManager.Delete(stringData);
		stringData = (char*)gStorageManager.New(newStrlength);
		stringDataLength = newStrlength + 1;
	}
	stringLength = newStrlength;
	if (stringLength)
		strncpy_s(stringData, stringDataLength, str, newStrlength);
	else
	{
		if (NULL != stringData && stringData != _stringData)
			gStorageManager.Delete(stringData);
		stringData = _stringData;
		*stringData = '\0';
		stringLength = 0;
		stringDataLength = DEFAULT_STRING_LENGTH;
	}	
 }

void String::trim(bool left, bool right)
{
	std::string buffer(stringData);
	if (left && right)
		boost::trim(buffer);
	if (left)
		boost::trim_left(buffer);
	if (right)
		boost::trim_right(buffer);
	stringLength = buffer.length() + 1;
	strcpy_s(stringData, stringDataLength, buffer.c_str());
}

bool String::find(const char* str) 
{ 
	return boost::find_first(std::string (stringData), str);
}

void String::replace(const char* str, const char* newStr)
{ 
	std::string buffer(stringData);
	boost::replace_first(buffer, str, newStr);
	stringLength = buffer.length() + 1;
	strcpy_s(stringData, stringDataLength, buffer.c_str());
}

size_t String::length() { return stringLength; }
size_t String::size() { return length(); }
void String::clear() { *stringData = '\0'; }
void String::erase(size_t length)
{
	if (length < stringLength)
		*(stringData + length) = '\0';
}

char String::at(size_t pos)
{
	if (stringDataLength < pos)
		return NULL;
	return *(stringData + pos);
}


